#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>

#include "double_list.h"

#define assert_debug(p) do { \
		if (!(p)) { \
			printf("%s:%d Warning: "#p" not Expect.\n", __func__, __LINE__);\
		} \
	}while (0)



 void print_int(void* data)
{
	printf("%d\t", (int)data);
}

dlist_ret_e count_sum(void *data,void **value)
{
	size_t ** cnt = (size_t **)value;
	
	*cnt = (size_t *)((size_t)(*cnt) + (size_t)(data));

	return DLIST_RET_OK;
}

dlist_ret_e dlist_get_sum(dlist_s *thiz,void **sum)
{
	return dlist_loop(thiz,count_sum,sum);
}
dlist_ret_e  count_max_value(void *data,void ** max_value)
{
	size_t ** cnt = (size_t **)max_value;
	
	if ((size_t)(data) > ((size_t)(*cnt))) {
		*cnt = (size_t *)(data);
	}
	return DLIST_RET_OK;
}
dlist_ret_e dlist_get_max_value(dlist_s *thiz,void **max_value)
{
	return dlist_loop(thiz,count_max_value,max_value);
}
void printf_str(void *data)
{
	if (data != NULL) {
		printf("%s\n",(char *)data);
	}
}
dlist_ret_e str_to_supper(void *data,void **value)
{
	char * str = (char *)data;

	value = value;
	
	while (*str != '\0') {
		*str = (char)toupper((*str));
		str++;
	}
	return DLIST_RET_OK;
}
dlist_ret_e dlist_str2supper(dlist_s *thiz)
{
	return dlist_loop(thiz,str_to_supper,NULL);
}
dlist_ret_e free_str_data(void *data,void **value)
{
	value = value;
	
	if (data != NULL) {
		free(data);
	}
	return DLIST_RET_OK;
}
void test_str2supper(void)
{
	dlist_s * dlist = dlist_create();
	int i = 0;
	int n = 2;
	char str[] = "abcdefghijkmnhbgdfgdfgsgsfh";
	char *str_except;
	char *p;

	char *data;
	
	/*append*/
	n = strlen(str);
	for (i = 0; i < n; i++) {
		data = (char *)malloc(sizeof(char)*(n-i+1));
		memcpy(data,str+i,n-i+1);
		assert(dlist_append(dlist, (void*)(data)) == DLIST_RET_OK);
		assert_debug(dlist_get_by_index(dlist, i, (void * *)&p) == DLIST_RET_OK);
		assert_debug((n-i) == strlen(p) && (strcmp(p,str+i) == 0));
	}
	dlist_printf(dlist, printf_str);
	/*convert to upper*/
	str_except = (char *)malloc(sizeof(char )*(n+1));
	memset(str_except,0,n+1);
	for (i=0; i<n; i++) {
		str_except[i] = (char) toupper(str[i]);	
	}
	printf("str_except:%s\n",str_except);

	assert_debug(dlist_str2supper(dlist) == DLIST_RET_OK);
	dlist_printf(dlist, printf_str);
	for (i = 0; i < n; i++) {
		assert_debug(dlist_get_by_index(dlist, i, (void * *)&p) == DLIST_RET_OK);
		assert_debug((n-i) == strlen(p) && (strcmp(p,str_except+i) == 0));
	}

	assert_debug(dlist_loop(dlist,free_str_data,NULL) == DLIST_RET_OK);
	dlist_destory(dlist);
}
int teset_dlist_interface(void)
{
	int i = 0;
	int n = 1000;
	dlist_s* dlist = dlist_create();
	int data;
	int j = 0;

	/*append*/
	for (i = 0; i < n; i++) {
		assert(dlist_append(dlist, (void*)i) == DLIST_RET_OK);
		assert_debug(dlist_get_by_index(dlist, i, (void * *)&data) == DLIST_RET_OK);
		assert_debug(data == i);
	}
	/*del*/
	for (i = 0; i < n; i++) {
		assert_debug(dlist_get_by_index(dlist,0, (void * *)&data) == DLIST_RET_OK);
		dlist_delete(dlist, 0);
		assert_debug(dlist_get_length(dlist) == n-i-1);
		assert_debug(data == (i));
	}
	for (i = 0; i < n; i++) {
		assert(dlist_preappend(dlist, (void*)i) == DLIST_RET_OK);
		assert_debug(dlist_get_by_index(dlist, 0, (void * *)&data) == DLIST_RET_OK);
		assert_debug(data == i);
	}

	for (i = 0; i < n; i++) {
		assert_debug(dlist_get_by_index(dlist,0, (void * *)&data) == DLIST_RET_OK);
		dlist_delete(dlist, 0);
		assert_debug(dlist_get_length(dlist) == n-i-1);
		assert_debug(data == (n-i-1));
	}
	/*set index, get index*/
	for (i = 0; i < n; i++) {
		assert(dlist_append(dlist, (void*)i) == DLIST_RET_OK);
		assert_debug(dlist_get_by_index(dlist, i, (void * *)&data) == DLIST_RET_OK);
		assert_debug(data == i);
	}	
	
	while (j < n) {
		for (i = 0; i < n; i++) {
			assert_debug(dlist_get_by_index(dlist, i, (void * *)&data) == DLIST_RET_OK);
			data++;
			assert_debug(dlist_set_by_index(dlist, i, (void *)data) == DLIST_RET_OK);
			assert_debug(dlist_get_by_index(dlist, i, (void * *)&data) == DLIST_RET_OK);
			assert_debug(data == (i+1+j));
		}
		j++;
	}
	dlist_destory(dlist);
	dlist = dlist_create();
	/*insert*/
	for (i=0; i<n; i++) {
		assert_debug(dlist_append(dlist, (void *) (i*2)) == DLIST_RET_OK);
	}
	dlist_printf(dlist, print_int);
	for (i=0; i<n; i++) {
		assert_debug(dlist_insert(dlist, i*2+1,(void *)(2*i+1)) == DLIST_RET_OK);
	}
	dlist_printf(dlist, print_int);
	for (i=0; i<2*n; i++) {
		assert_debug(dlist_get_by_index(dlist,i, (void * * )&data) == DLIST_RET_OK);
		assert_debug(data == i);
	}
	/*del  again from Middle*/
	for (i=0; i<2*n-2; i++) {
		assert_debug(dlist_delete(dlist,1) == DLIST_RET_OK);
		assert_debug(dlist_get_by_index(dlist,1, (void * * )&data) == DLIST_RET_OK);
		assert_debug(data == i+2);
	}
	assert_debug(dlist_get_by_index(dlist,0, (void * * )&data) == DLIST_RET_OK);
	assert_debug(data == 0);
	assert_debug(dlist_get_by_index(dlist,1, (void * * )&data) == DLIST_RET_OK);
	assert_debug(data == 2*n-1);
	dlist_printf(dlist, print_int);
	/*del  again from end*/
	dlist_destory(dlist);
	dlist = dlist_create();
	for (i=0; i<n; i++) {
		assert_debug(dlist_append(dlist, (void *) (i)) == DLIST_RET_OK);
	}
	for (i=n; i>1; i--) {
		assert_debug(dlist_delete(dlist, i-1)== DLIST_RET_OK);
		assert_debug(dlist_get_by_index(dlist,i-2, (void * * )&data) == DLIST_RET_OK);
		assert_debug(data == i-2);
	}
	dlist_printf(dlist, print_int);
	dlist_destory(dlist);
	dlist = dlist_create();
	for (i=0; i<n; i++) {
		assert_debug(dlist_append(dlist, (void *) (i)) == DLIST_RET_OK);
	}
	for (i=n; i>1; i--) {
		assert_debug(dlist_delete(dlist, -1)== DLIST_RET_OK);
		assert_debug(dlist_get_by_index(dlist,i-2, (void * * )&data) == DLIST_RET_OK);
		assert_debug(data == i-2);
	}
	dlist_printf(dlist, print_int);
	dlist_destory(dlist);

	return 0;
}

void test_get_sum(void)
{
	int i;
	int n = 100;
	dlist_s *dlist;
	size_t sum = 0;
	size_t sum_expect = 0;
	
	dlist = dlist_create();
	for (i=0; i<n; i++) {
		assert_debug(dlist_append(dlist, (void *) (i)) == DLIST_RET_OK);
		sum_expect += i;
	}
	assert_debug(dlist_get_sum(dlist, (void **)(&sum)) == DLIST_RET_OK);
	assert_debug(sum_expect == sum);
	
	dlist_printf(dlist, print_int);
	dlist_destory(dlist);
}
void test_get_max_value(void)
{
	int i;
	int n = 100;
	dlist_s *dlist;
	size_t sum = 0;
	size_t sum_expect = 0;

	dlist = dlist_create();
	for (i=0; i<n; i++) {
		assert_debug(dlist_append(dlist, (void *) (i)) == DLIST_RET_OK);
		sum_expect = i;
	}
	assert_debug(dlist_get_max_value(dlist, (void **)(&sum)) == DLIST_RET_OK);
	assert_debug(sum_expect == sum);
	
	dlist_printf(dlist, print_int);
	dlist_destory(dlist);
}

int main(int argc, char* argv[])
{
	test_get_sum();

	test_get_max_value();

	test_str2supper();
	
	return 1;
}
